package stream;

import java.util.List;
import java.util.Spliterator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.testng.annotations.Test;

/**
 *
 * Spliterator，可拆分的迭代器，和Iterator一样，Spliterator也用于遍历数据源中的元素，但它是为了并行执行而设计的
 * 是泛型接口，所以必然有一个类型
 * 有一个final类Spliterators，
 *
 *
 * public static final int ORDERED    = 0x00000010; 表示元素是有序的（每一次遍历结果相同）
 * public static final int DISTINCT   = 0x00000001; 表示元素不重复
 * public static final int SORTED     = 0x00000004; 表示元素是按一定规律进行排列（有指定比较器）
 * public static final int SIZED      = 0x00000040; 表示大小是固定的
 * public static final int NONNULL    = 0x00000100; 表示没有null元素
 * public static final int IMMUTABLE  = 0x00000400; 表示元素不可变
 * public static final int CONCURRENT = 0x00001000; 表示迭代器可以多线程操作
 * public static final int SUBSIZED   = 0x00004000; 表示子Spliterators都具有SIZED特性
 *
 */
public class SpliteratorBase {

    static class CustBook {
        private String name;

        public CustBook(String name) {
            this.name = name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    static class CustBookCounter {
        private int counter;

        public CustBookCounter accumulate(CustBook custBook) {
            return new CustBookCounter(counter+1);
        }

        public CustBookCounter combine(CustBookCounter custBookCounter) {
            return new CustBookCounter(
                counter + custBookCounter.getCounter());
        }

        public CustBookCounter(int counter) {
            this.counter = counter;
        }

        public int getCounter() {
            return counter;
        }
    }

    /**
     * 调用tryAdvance方法，
     * @param spliterator
     * @return
     */
    public String call(Spliterator<CustBook> spliterator) {
        int current = 0;
        // tryAdvance方法只要还有元素未被处理就会返回true
        while (spliterator.tryAdvance(a -> a.setName("test name".concat("- add new name")))) {
            current++;
        }

        return Thread.currentThread().getName() + ":" + current;
    }

    /**
     * 生成1000条数据
     */
    public static List<CustBook> generateElements() {
        return Stream.generate(() -> new CustBook("cust book"))
            .limit(1000)
            .collect(Collectors.toList());
    }

    @Test
    private void useTrySplit() {
        // Collection的都有spliterator()方法，所以可以直接调用
        Spliterator<CustBook> split1 = SpliteratorBase.generateElements().spliterator();
        // 调用一次trySplit，将list分成两个部分，每部分500条数据
        Spliterator<CustBook> split2 = split1.trySplit();

        // 元素数量的估计值
        System.out.println("before tryAdvance: " + split1.estimateSize());

        // 表示这个spliterator的特征，有8种特征ORDERED、DISTINCT、SORTED...
        // 一个Spliterator可以有多个特征，多个特征进行or运算，最后得到最终的characteristics
        //  or运算的值结果为16464，转换为16进制：Ox4050 = ORDERED or SIZED or SUBSIZED 这三个的或运算。
        // 这也是ArrayList的基本特征
        System.out.println("Characteristics " + split1.characteristics());

        System.out.println(call(split1));
        System.out.println(call(split2));

        // 调用tryAdvance之后，estimateSize为0，表示所有的元素都已经被处理完毕
        System.out.println("after tryAdvance " + split1.estimateSize());
    }
}
